package com.hex.ds.hdrs.engine.service;

import com.hex.bigdata.hbda.base.Page;
import com.hex.ds.hdrs.agent.service.AgentConfService;
import com.hex.ds.hdrs.app.po.AppConf;
import com.hex.ds.hdrs.app.service.impl.AppConfService;
import com.hex.ds.hdrs.common.annotation.AppCodeVerification;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.helper.RamHelper;
import com.hex.ds.hdrs.common.utils.BaseUtil;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.common.utils.ListUtil;
import com.hex.ds.hdrs.cron.dto.CronTaskDefDto;
import com.hex.ds.hdrs.cron.service.CronTaskDefService;
import com.hex.ds.hdrs.cron.service.CronTaskService;
import com.hex.ds.hdrs.engine.exec.DispatcherExec;
import com.hex.ds.hdrs.engine.exec.ProcessorExec;
import com.hex.ds.hdrs.engine.manager.RunningManager;
import com.hex.ds.hdrs.engine.manager.ToDoManager;
import com.hex.ds.hdrs.engine.manager.ToRunManager;
import com.hex.ds.hdrs.engine.vo.DispatcherExecVo;
import com.hex.ds.hdrs.engine.vo.ProcessorExecVo;
import com.hex.ds.hdrs.period.job.po.JobTask;
import com.hex.ds.hdrs.period.job.po.PeriodJob;
import com.hex.ds.hdrs.period.job.service.PeriodJobService;
import com.hex.ds.hdrs.period.task.po.PeriodTask;
import com.hex.ds.hdrs.period.task.service.PeriodTaskDefService;
import com.hex.ds.hdrs.period.task.service.PeriodTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class RamService {

    @Autowired
    private AgentConfService agentConfService;
    @Autowired
    private CronTaskService cronTaskService;
    @Autowired
    private AppConfService appConfService;
    @Autowired
    private PeriodJobService periodJobService;
    @Autowired
    private RunningManager runningManager;
    @Autowired
    private ToRunManager toRunManager;
    @Autowired
    private ToDoManager toDoManager;
    @Autowired
    private PeriodTaskService periodTaskService;
    @Autowired
    private PeriodTaskDefService periodTaskDefService;
    @Autowired
    private CronTaskDefService cronTaskDefService;
    @Autowired
    private ProcessorService processorService;
    @Autowired
    private DispatcherService dispatcherService;

    /**
     * @Method: findTaskRunInfCurrentAppInfo
     * @Param: []
     * @Return: java.util.Map
     * @Description: 查询今日任务实例状态数量汇总
     * @Author: ji.tang
     * @Date: 2022/6/8 15:53
     * @Version: V1.0
     */
    public Map findTaskRunInfCurrentAppInfo(String appCode) {
        String periodBizDate = HdrsDateUtil.getCurrentDate();
        String cronExectStTs = HdrsDateUtil.getNormalDate(new Date());
        List<Map> periodMap = this.getTaskStatusCount(periodBizDate, appCode, Const.TASK_TYPE_PERIOD);
        List<Map> cronMap = this.getTaskStatusCount(cronExectStTs, appCode, Const.TASK_TYPE_CRON);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_NOT_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_NOT_HIS, cronMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * 获取所有应用的任务执行情况
     *
     * @return
     */
    public Map findAllJobInfByCurrentUser() {
        List<Map> periodMap = this.getTaskStatusCount(null, null, Const.TASK_TYPE_PERIOD);
        List<Map> cronMap = this.getTaskStatusCount(null, null, Const.TASK_TYPE_CRON);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_IS_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_IS_HIS, cronMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * @Method: getPeriodTaskStatusCount
     * @Param: [bizDate, type]
     * @Return: java.util.List<java.util.Map>
     * @Description: 周期/定时任务实例状态数量
     * @Author: ji.tang
     * @Date: 2022/6/16 16:37
     * @Version: V1.0
     */
    public List<Map> getTaskStatusCount(String bizDate, String appCode, String taskType) {
        Map paramMap = new HashMap(16);
        if (StringUtils.isNotBlank(bizDate)) {
            paramMap.put("bizDate", bizDate);
        }
        if (StringUtils.isBlank(appCode)) {//首页查询
            String username = BaseUtil.getUserId();
            List<AppConf> appConfList = this.appConfService.findAppByCurrentUser(username);
            List<String> appCodeList = appConfList.stream().map(AppConf::getAppCode).collect(Collectors.toList());
            paramMap.put("appCodeList", appCodeList);
            paramMap.put("username", username);
        } else if (StringUtils.isNotBlank(appCode)) {//应用下查询
            paramMap.put("appCode", appCode);
        }
        if (taskType.equals(Const.TASK_TYPE_PERIOD)) {
            return this.periodTaskService.selectUnionCountByTaskStatus(paramMap);
        } else {
            return this.cronTaskService.selectUnionCountByTaskStatus(paramMap);
        }
    }

    /**
     * @Method: setTaskStatusParam
     * @Param: [taskType, isHis, maps]
     * @Return: java.util.Map
     * @Description: 设置任务状态返回对象
     * @Author: ji.tang
     * @Date: 2022/6/16 17:22
     * @Version: V1.0
     */
    public Map setTaskStatusParam(String taskType, String isHis, List<Map> maps) {
        Map map = new HashMap();
        if (CollectionUtils.isEmpty(maps)) {
            return map;
        }
        for (Map m : maps) {
            if (taskType.equals(Const.TASK_TYPE_PERIOD)) {//周期任务
                if (isHis.equals(Const.TASK_COUNT_NOT_HIS)) {//当日
                    if (m.containsKey("TASK_STATUS")) {
                        if (Const.TASK_TODO_RUN.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskTodoCount", m.get("COUNT"));
                        } else if (Const.TASK_RUNNING.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskRunningCount", m.get("COUNT"));
                        } else if (Const.TASK_SUCCESS.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskSuccessCount", m.get("COUNT"));
                        } else if (Const.TASK_FAIL.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskFailCount", m.get("COUNT"));
                        }
                    }
                } else {//历史
                    if (m.containsKey("TASK_STATUS")) {
                        if (Const.TASK_TODO_RUN.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskTodoTotalCount", m.get("COUNT"));
                        } else if (Const.TASK_RUNNING.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskRunningTotalCount", m.get("COUNT"));
                        } else if (Const.TASK_SUCCESS.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskSuccessTotalCount", m.get("COUNT"));
                        } else if (Const.TASK_FAIL.equals(m.get("TASK_STATUS"))) {
                            map.put("cycleTaskFailTotalCount", m.get("COUNT"));
                        }
                    }
                }
            } else if (taskType.equals(Const.TASK_TYPE_CRON)) {//实时任务
                if (isHis.equals(Const.TASK_COUNT_NOT_HIS)) {//当日
                    if (m.containsKey("EXEC_STATUS")) {
                        if (Const.CRON_TASK_RUNNING.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskRunningCount", m.get("COUNT"));
                        } else if (Const.CRON_TASK_SUCCESS.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskSuccessCount", m.get("COUNT"));
                        } else if (Const.CRON_TASK_FAIL.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskFailCount", m.get("COUNT"));
                        } else {
                            map.put("cronTaskTodoCount", 0);
                        }
                    }
                } else {//历史
                    if (m.containsKey("EXEC_STATUS")) {
                        if (Const.CRON_TASK_RUNNING.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskRunningTotalCount", m.get("COUNT"));
                        } else if (Const.CRON_TASK_SUCCESS.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskSuccessTotalCount", m.get("COUNT"));
                        } else if (Const.CRON_TASK_FAIL.equals(m.get("EXEC_STATUS"))) {
                            map.put("cronTaskFailTotalCount", m.get("COUNT"));
                        } else {//实时任务没有待处理，默认为0
                            map.put("cronTaskTodoCount", 0);
                        }
                    }
                }
            }
        }

        return map;
    }

    /**
     * 获取当前应用，不同业务日期作业数量
     *
     * @return
     */
    @AppCodeVerification(paramObject = String.class)
    public List getCycleJobRunInfCurrentApp(String appCode) {
        log.info("进入了【AgentConfService类中的getCycleJobRunInfCurrentApp方法】");
        Map resultMap = RamHelper.getCycleJobRunInfCurrentApp(appCode);
        return new ArrayList<Map>(resultMap.values());
    }

    public Map getRamJobTaskInf(String jobCode, String bizDate) {
        Map resultMap = new HashMap();
        JobTask jobTask = toDoManager.getJob(jobCode);
        if (jobTask != null && bizDate.equals(jobTask.getBizDate())) {
            resultMap.put("jobInf", jobTask.getPeriodJob());
            resultMap.put("taskList", jobTask.getPeriodTasks());
            return resultMap;
        }
        jobTask = toRunManager.getJob(jobCode);
        if (jobTask != null && bizDate.equals(jobTask.getBizDate())) {
            resultMap.put("jobInf", jobTask.getPeriodJob());
            resultMap.put("taskList", jobTask.getPeriodTasks());
            return resultMap;
        }
        jobTask = runningManager.getJob(jobCode);
        if (jobTask != null && bizDate.equals(jobTask.getBizDate())) {
            resultMap.put("jobInf", jobTask.getPeriodJob());
            resultMap.put("taskList", jobTask.getPeriodTasks());
            return resultMap;
        }
        PeriodJob periodJob = this.periodJobService.queryByJobCodeAndBizDate(jobCode, bizDate);
        List<PeriodTask> taskList = this.periodTaskService.qryTaskListInJob(jobCode, bizDate);
        resultMap.put("jobInf", periodJob);
        resultMap.put("taskList", taskList);
        return resultMap;
    }

    public Map getJobTaskInf(Map paramMap) {
        String jobCode = (String) paramMap.get("jobCode");
        String bizDate = (String) paramMap.get("bizDate");
        return this.getRamJobTaskInf(jobCode, bizDate);
    }

    public Map<String, Integer> findAdminTopData() {
        Map<String, Integer> dataMap = new HashMap();
        dataMap.put("nodeNum", this.agentConfService.qryAgentCount());
        dataMap.put("appNum", this.appConfService.qryAppCount(new HashMap()));
        dataMap.put("cycleTaskNum", this.periodTaskDefService.qryTaskDefCount());
        dataMap.put("cronTaskNum", this.cronTaskDefService.queryList(new CronTaskDefDto()).size());
        return dataMap;
    }


    /**
     * 查询内存处理器线程
     *
     * @param processorExecVO
     * @param page
     * @return
     */
    public List<ProcessorExecVo> qryProThread(ProcessorExecVo processorExecVO, Page page) {
        List<ProcessorExecVo> threadVOList = new ArrayList<ProcessorExecVo>();
        List<ProcessorExec> threadList = processorService.getThreadList();
        List<ProcessorExec> threadListShow = new ArrayList<>();

        if (StringUtils.isNotBlank(processorExecVO.getThreadName())) {
            for (ProcessorExec processorExec : threadList) {
                if (processorExec.getThreadName().equals(processorExecVO.getThreadName())) {
                    threadListShow.add(processorExec);
                }
            }
        }
        if (StringUtils.isBlank(processorExecVO.getThreadName())) {
            threadListShow = threadList;
        }
        for (ProcessorExec processorExec : threadListShow) {
            ProcessorExecVo processorExecVo2 = new ProcessorExecVo();
            processorExecVo2.setThreadName(processorExec.getThreadName());
            processorExecVo2.setRun(String.valueOf(processorExec.getRun()));
            processorExecVo2.setStop(String.valueOf(processorExec.getStop()));
            processorExecVo2.setRunningFlag(String.valueOf(processorExec.getRunningFlag()));
            threadVOList.add(processorExecVo2);
        }
        return this.formatProListPage(threadVOList, page);
    }

    /**
     * 查询内存分发器线程
     *
     * @param dispatcherExecVO
     * @param page
     * @return
     */
    public List<DispatcherExecVo> qryDisThread(DispatcherExecVo dispatcherExecVO, Page page) {
        List<DispatcherExecVo> threadVOList = new ArrayList<DispatcherExecVo>();
        List<DispatcherExec> threadList = dispatcherService.getThreadList();
        List<DispatcherExec> threadListShow = new ArrayList<>();

        if (StringUtils.isNotBlank(dispatcherExecVO.getThreadName())) {
            for (DispatcherExec dispatcherExec : threadList) {
                if (dispatcherExec.getThreadName().equals(dispatcherExecVO.getThreadName())) {
                    threadListShow.add(dispatcherExec);
                }
            }
        }
        if (StringUtils.isNotBlank(dispatcherExecVO.getGroupCode())) {
            for (DispatcherExec dispatcherExec : threadList) {
                if (dispatcherExec.getGroupCode().equals(dispatcherExecVO.getGroupCode())) {
                    threadListShow.add(dispatcherExec);
                }
            }
        }
        if (StringUtils.isBlank(dispatcherExecVO.getGroupCode())
                && StringUtils.isBlank(dispatcherExecVO.getThreadName())) {
            threadListShow = threadList;
        }
        for (DispatcherExec processorExec : threadListShow) {
            DispatcherExecVo processorExecVO2 = new DispatcherExecVo();
            processorExecVO2.setThreadName(processorExec.getThreadName());
            processorExecVO2.setGroupCode(processorExec.getGroupCode());
            processorExecVO2.setRun(String.valueOf(processorExec.getRun()));
            processorExecVO2.setStop(String.valueOf(processorExec.getStop()));
            processorExecVO2.setRunningFlag(String.valueOf(processorExec.getRunningFlag()));
            threadVOList.add(processorExecVO2);
        }
        return this.formatDisListPage(threadVOList, page);
    }

    /**
     * 分页处理
     *
     * @param taskList
     * @param page
     * @return
     */
    public List<ProcessorExecVo> formatProListPage(List<ProcessorExecVo> taskList, Page page) {
        if (ListUtil.isEmpty(taskList)) {
            page.setTotal(0);
            return taskList;
        }

        page.setTotal(taskList.size());
        Integer startIndex = page.getPageIndex() * page.getPageSize();
        Integer endIndex = (page.getPageIndex() + 1) * page.getPageSize();
        if (startIndex == taskList.size()) {
            startIndex = (page.getPageIndex() - 1) * page.getPageSize();
            page.setPageIndex(page.getPageIndex() - 1);
        } else if (startIndex > taskList.size()) {
            Integer pageIndex = taskList.size() / page.getPageSize();
            startIndex = pageIndex * page.getPageSize();
            page.setPageIndex(pageIndex);
        }
        endIndex = (endIndex < taskList.size()) ? endIndex : taskList.size();
        return taskList.subList(startIndex, endIndex);
    }

    /**
     * 分页处理
     *
     * @param taskList
     * @param page
     * @return
     */
    public List<DispatcherExecVo> formatDisListPage(List<DispatcherExecVo> taskList, Page page) {
        if (ListUtil.isEmpty(taskList)) {
            page.setTotal(0);
            return taskList;
        }

        page.setTotal(taskList.size());
        Integer startIndex = page.getPageIndex() * page.getPageSize();
        Integer endIndex = (page.getPageIndex() + 1) * page.getPageSize();
        if (startIndex == taskList.size()) {
            startIndex = (page.getPageIndex() - 1) * page.getPageSize();
            page.setPageIndex(page.getPageIndex() - 1);
        } else if (startIndex > taskList.size()) {
            Integer pageIndex = taskList.size() / page.getPageSize();
            startIndex = pageIndex * page.getPageSize();
            page.setPageIndex(pageIndex);
        }
        endIndex = (endIndex < taskList.size()) ? endIndex : taskList.size();
        return taskList.subList(startIndex, endIndex);
    }

    /**
     * @Method: findHisTaskRunInfCurrentApp
     * @Param: []
     * @Return: java.util.Map
     * @Description: 获取当前应用历史任务执行情况
     * @Author: ji.tang
     * @Date: 2022/6/14 18:45
     * @Version: V1.0
     */
    public Map findHisTaskRunInfCurrentApp(String appCode) {
        List<Map> periodMap = this.getTaskStatusCount(null, appCode, Const.TASK_TYPE_PERIOD);
        List<Map> cronMap = this.getTaskStatusCount(null, appCode, Const.TASK_TYPE_CRON);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_IS_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_IS_HIS, cronMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * @Method: findPeriodTaskCountTopDataNotApp
     * @Param: []
     * @Return: java.util.Map
     * @Description: 查询首页周期任务当日/历史各状态数量
     * @Author: ji.tang
     * @Date: 2022/6/17 15:56
     * @Version: V1.0
     */
    public Map findPeriodTaskCountTopDataNotApp() {
        String periodBizDate = HdrsDateUtil.getCurrentDate();
        List<Map> periodMap = this.getTaskStatusCount(periodBizDate, null, Const.TASK_TYPE_PERIOD);
        List<Map> periodHisMap = this.getTaskStatusCount(null, null, Const.TASK_TYPE_PERIOD);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_NOT_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_IS_HIS, periodHisMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * @Method: findCronTaskCountTopDataNotApp
     * @Param: []
     * @Return: java.util.Map
     * @Description: 查询首页定时任务当日/历史各状态数量
     * @Author: ji.tang
     * @Date: 2022/6/17 16:15
     * @Version: V1.0
     */
    public Map findCronTaskCountTopDataNotApp() {
        String cronExectStTs = HdrsDateUtil.getNormalDate(new Date());
        List<Map> periodMap = this.getTaskStatusCount(cronExectStTs, null, Const.TASK_TYPE_CRON);
        List<Map> periodHisMap = this.getTaskStatusCount(null, null, Const.TASK_TYPE_CRON);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_NOT_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_IS_HIS, periodHisMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * @Method: findCronTaskCountTopData
     * @Param: []
     * @Return: java.util.Map
     * @Description: 查询应用下定时任务当日/历史各状态数量
     * @Author: ji.tang
     * @Date: 2022/6/17 16:16
     * @Version: V1.0
     */
    public Map findCronTaskCountTopData(String appCode) {
        String cronExectStTs = HdrsDateUtil.getNormalDate(new Date());
        List<Map> periodMap = this.getTaskStatusCount(cronExectStTs, appCode, Const.TASK_TYPE_CRON);
        List<Map> periodHisMap = this.getTaskStatusCount(null, appCode, Const.TASK_TYPE_CRON);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_NOT_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_CRON, Const.TASK_COUNT_IS_HIS, periodHisMap);
        map1.putAll(map2);
        return map1;
    }

    /**
     * @Method: findPeriodTaskCountTopData
     * @Param: []
     * @Return: java.util.Map
     * @Description: 查询应用下周期任务当日/历史各状态数量
     * @Author: ji.tang
     * @Date: 2022/6/17 16:20
     * @Version: V1.0
     */
    public Map findPeriodTaskCountTopData(String appCode) {
        String periodBizDate = HdrsDateUtil.getCurrentDate();
        List<Map> periodMap = this.getTaskStatusCount(periodBizDate, appCode, Const.TASK_TYPE_PERIOD);
        List<Map> periodHisMap = this.getTaskStatusCount(null, appCode, Const.TASK_TYPE_PERIOD);
        Map map1 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_NOT_HIS, periodMap);
        Map map2 = this.setTaskStatusParam(Const.TASK_TYPE_PERIOD, Const.TASK_COUNT_IS_HIS, periodHisMap);
        map1.putAll(map2);
        return map1;
    }
}
